package com.ruoyi.manufacturer.common;

import com.ruoyi.alarm.domain.AlarmWarning;
import com.ruoyi.base.domain.BaseDevice;
import com.ruoyi.manufacturer.IPlatform;
import com.ruoyi.manufacturer.MessageVo;
import com.ruoyi.push.PushService;
import com.ruoyi.third.domain.ThirdError;
import com.ruoyi.third.domain.ThirdMessage;
import com.ruoyi.third.service.IThirdErrorService;
import com.ruoyi.third.service.IThirdEventService;
import com.ruoyi.third.service.IThirdMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 第三方接入的公共代码
 * 正常逻辑如下：
 * 1、等待推送消息，或主动接连对方平台，等待消息
 * 2、接收到消息后进行解析
 * 2.1 先提取出设备信息，判断本地是否存在，如果不存在，就封装成标准设备信息，先查询是否存在，不存在就新增
 * 2.3 再提取业务数据，如告警，监测状态等，进行对应处理
 * 3、记录消息，如果处理失败，就记录错误日志
 */
@Service
public abstract class CommonHandler implements IPlatform {
    @Autowired
    protected IThirdMessageService thirdMessageService;
    @Autowired
    protected IThirdErrorService thirdErrorService;
    @Autowired
    protected IThirdEventService thirdEventService;
    @Autowired
    protected DeviceHandler deviceHandler;
    @Autowired
    protected AlarmHandler alarmHandler;
    @Autowired
    protected PushService pushService;

    @Override
    public boolean process(Object msg) {
        boolean ret = true;
        String msgType = null;
        Map<String, BaseDevice> deviceMap = new HashMap<>();
        try {
            MessageVo messageVo = parseMessage(msg);
            if (messageVo.getType() == null || messageVo.getDevice() == null || messageVo.getDevice().isEmpty()) {
                //空消息体，可能是心跳数据
                msgType = "0";
                return true;
            }
            msgType = messageVo.getType();

            //先处理设备信息
            for (MessageVo.Device device : messageVo.getDevice()) {
                BaseDevice baseDevice = deviceHandler.processDevice(device, getPfCode());
                if (baseDevice != null) {
                    deviceMap.put(device.getCode(), baseDevice);
                }
            }

            //再处理告警消息
            for (MessageVo.Alarm alarm : messageVo.getAlarm()) {
                BaseDevice baseDevice = deviceMap.get(alarm.getDeviceCode());
                if (baseDevice != null) {
                    AlarmWarning alarmWarning = alarmHandler.processAlarm(alarm, baseDevice);
                    if(alarmWarning != null) {
                        //触发告警规则
                        alarmHandler.triggerAlarmRule(alarmWarning, baseDevice);
                        //推送告警消息
                        pushService.pushAlarm(alarmWarning);
                    }
                    onAlarm(alarm, baseDevice);
                }else{
                    logError(getPfCode(), ThirdError.TYPE_OTHER, "设备处理失败,无法处置告警", msg.toString());
                }
            }

            //最后处理监测数据
            for (MessageVo.Business business : messageVo.getBusiness()) {
                BaseDevice baseDevice = deviceMap.get(business.getDeviceCode());
                if (baseDevice != null) {
                    processBusiness(business, baseDevice);
                }else{
                    logError(getPfCode(), ThirdError.TYPE_OTHER, "设备处理失败,无法处置监测数据", msg.toString());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            logError(getPfCode(), ThirdError.TYPE_FAILED, msg.toString(), e.getMessage());
            ret = false;
        }finally {
            Optional<BaseDevice> baseDevice = deviceMap.values().stream().findFirst();
            logMessage(baseDevice.isPresent() ? baseDevice.get() : null, msgType,  msg.toString(), ret);
        }

        return ret;
    }

    /**
     * 解析消息体
     * @param msg 消息内容
     * @return 标准消息体
     */
    public abstract MessageVo parseMessage(Object msg);

    /**
     * 自定义的告警事件的联动处理,除了保存告警消息/推送消息/告警联动规则之外 TODO
     * @param alarm 告警
     * @param device 设备
     * @return
     */
    public abstract void onAlarm(MessageVo.Alarm alarm, BaseDevice device);

    /**
     * 处理监测数据流程,默认是存在alarm_data表 TODO
     * @param business 数据
     * @param device 设备
     * @return
     */
    public boolean processBusiness(MessageVo.Business business, BaseDevice device){
        return alarmHandler.processData(business, device);
    }


    /**
     * 记录接收到的消息
     * @param baseDevice 设备
     * @param type 消息类型
     * @param msg 消息
     * @param result 处理结果
     */
    public void logMessage(BaseDevice baseDevice, String type, String msg, Boolean result){
        ThirdMessage thirdMessage = new ThirdMessage();
        thirdMessage.setPfCode(getPfCode());
        thirdMessage.setContent(msg);
        thirdMessage.setType(type);
        thirdMessage.setResults(result?"1":"0");
        thirdMessage.setMsgTime(new Date());
        thirdMessage.setDeviceId(baseDevice == null ? null : baseDevice.getId());
        thirdMessage.setDeviceCode(baseDevice == null ? null : baseDevice.getCode());
        thirdMessageService.insertThirdMessage(thirdMessage);
    }

    /**
     * 记录处理消息过程中的错误
     * @param pfCode 平台
     * @param type 错误类型
     * @param msg 消息内容
     * @param error 错误信息
     */
    public void logError(String pfCode, String type,  String msg, String error){
        ThirdError thirdError = new ThirdError();
        thirdError.setPfCode(pfCode);
        thirdError.setType(type);
        thirdError.setContent(msg);
        thirdError.setError(error);
        thirdError.setLogTime(new Date());
        thirdErrorService.insertThirdError(thirdError);
    }
}
